﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using PanGu;
using NLog;
using LingDong.NaiveCrawler;
using System.Threading;
using LingDong.IndexReader;
using LingDong.KeywordExtract;

namespace LingDong.PictureKeywords
{
    public class Visibility
    {
        #region Download

        public static void DownloadC1C2FromGoogle(List<string> content, string outputFile)
        {
            DownloadC1C2(content, outputFile, GoogleCrawl.GetTextResultNumber, GoogleCrawl.GetImageResultNumber);
        }

        public static void DownloadC1C2FromBaidu(List<string> content, string outputFile)
        {
            DownloadC1C2(content, outputFile, BaiduCrawl.GetTextResultNumber, BaiduCrawl.GetImageResultNumber);
        }

        private static void DownloadC1C2(List<string> content, string outputFile, 
                                         GetResultNumberMethod textMethod, GetResultNumberMethod imageMethod)
        {
            Segment.Init();
            Dictionary<string, int> keywordDic = new Dictionary<string, int>();

            logger.Debug("Segment begins");
            foreach (string line in content)
            {
                var wordList = new Segment().DoSegment(line);
                foreach (WordInfo word in wordList)
                {
                    keywordDic[word.Word] = 1;
                }
            }
            logger.Debug("Segment ends, total words: " + keywordDic.Count);

            using (StreamWriter sw = new StreamWriter(outputFile, false))
            {
                int count = 0;
                foreach (string keyword in keywordDic.Keys)
                {
                    count++;
                    if (count <= 14370)
                        continue;

                    int c1 = textMethod(keyword);
                    int c2 = imageMethod(keyword);
                    sw.WriteLine("{0}\t{1}\t{2}", keyword, c1, c2);
                    sw.Flush();

                    if (count % 100 == 0)
                        Console.WriteLine(count);

                    Thread.Sleep(1200);
                }
            }
        }

        #endregion


        #region Download Again

        public static void DownloadC1C2FromBaidu(Dictionary<string, KeyValuePair<int, int>> terms, string outputFile)
        {
            DownloadC1C2(terms, outputFile, BaiduCrawl.GetTextResultNumber, BaiduCrawl.GetImageResultNumber);
        }

        public static void DownloadC1C2FromGoogle(Dictionary<string, KeyValuePair<int, int>> terms, string outputFile)
        {
            DownloadC1C2(terms, outputFile, GoogleCrawl.GetTextResultNumber, GoogleCrawl.GetImageResultNumber);
        }

        private static void DownloadC1C2(Dictionary<string, KeyValuePair<int, int>> terms, string outputFile,
                                         GetResultNumberMethod textMethod, GetResultNumberMethod imageMethod)
        {
            using (StreamWriter sw = new StreamWriter(outputFile, false))
            {
                int count = 0;
                foreach (KeyValuePair<string, KeyValuePair<int, int>> pair in terms)
                {
                    string keyword = pair.Key;
                    int c1 = (pair.Value.Key == 0) ? textMethod(keyword) : pair.Value.Key;
                    int c2 = (pair.Value.Value == 0) ? imageMethod(keyword) : pair.Value.Value;

                    sw.WriteLine("{0}\t{1}\t{2}", keyword, c1, c2);
                    sw.Flush();

                    if (++count % 100 == 0)
                        Console.WriteLine(count);
                    if (pair.Value.Key == 0 || pair.Value.Value == 0)
                        Thread.Sleep(1200);
                }
            }
        }

        #endregion


        #region Compute

        public static void Init(string downloadResultFile)
        {
            visResult = new Dictionary<string, double>();
            using (StreamReader sr = new StreamReader(downloadResultFile))
            {
                while (!sr.EndOfStream)
                {
                    string line = sr.ReadLine();
                    string[] terms = line.Split();
                    int c1 = Convert.ToInt32(terms[1]);
                    int c2 = Convert.ToInt32(terms[2]);
                    visResult[terms[0]] = GetVis(c1, c2);
                }
            }

            defaultVis = GetVis(0, 0);

            index = new Index();
        }

        /// <summary>
        /// Should call Init() first
        /// </summary>
        /// <param name="url"></param>
        /// <param name="html"></param>
        /// <returns></returns>
        public static List<KeyValuePair<string, string>> GetPictureKeywords(string url, string html)
        {
            string keywords = KeywordExtracter.GetHTMLKeywordsString(html, index);
            List<KeyValuePair<string, string>> baselineResult = Baseline.GetPictureKeywords(url, html);
            List<KeyValuePair<string, string>> result = new List<KeyValuePair<string, string>>();
            foreach (KeyValuePair<string, string> pair in baselineResult)
            {
                result.Add(new KeyValuePair<string, string>(pair.Key, keywords));
            }
            return result;
        }

        private static string GetTopVisKeywords(string content)
        {
            Segment.Init();
            var words = new Segment().DoSegment(content);

            Dictionary<string, double> keywords = new Dictionary<string, double>();
            foreach (WordInfo word in words)
            {
                double vis = GetTermVis(word.Word);
                keywords[word.Word] = vis;
            }
            StringBuilder topKeywords = new StringBuilder();
            keywords.OrderByDescending(p => p.Value).Take(Settings.VISTopKeywordsNum).
                ToList().ForEach(w => { topKeywords.Append(w.Key); topKeywords.Append('\t'); });
            return topKeywords.ToString();
        }

        private static double GetTermVis(string term)
        {
            double vis;
            if (visResult.TryGetValue(term, out vis))
                return vis;
            return 0.0;
        }

        private static double GetVis(int c1, int c2)
        {
            c1 += 2;
            c2 += 2;
            double baseNum = ((double)c1 + 1e-9) / ((double)c2 + 1e-9);
            double powNum = -Math.Log(Settings.GoogleIndexPageNumber, c2);
            return Math.Pow(baseNum, powNum);
        }

        private static Index index;

        #endregion


        #region Private Members

        private static Logger logger = LogManager.GetCurrentClassLogger();
        private delegate int GetResultNumberMethod(string query);

        private static Dictionary<string, double> visResult;
        private static double defaultVis;

        #endregion
    }
}
